package
{
	import com.bit101.components.CheckBox;
	import com.bit101.components.ComboBox;
	import com.bit101.components.Component;
	import com.bit101.components.HBox;
	import com.bit101.components.HUISlider;
	import com.bit101.components.InputText;
	import com.bit101.components.Label;
	import com.bit101.components.Panel;
	import com.bit101.components.PushButton;
	import com.bit101.components.Text;
	import com.bit101.components.TextArea;
	import com.bit101.components.UISlider;
	import com.bit101.components.VBox;
	import com.bit101.components.VUISlider;
	import com.bit101.components.Window;
	
	import flash.desktop.Clipboard;
	import flash.desktop.ClipboardFormats;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TextEvent;
	import flash.external.ExternalInterface;
	import flash.filters.GlowFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.FileReference;
	import flash.net.getClassByAlias;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	
	import flashx.textLayout.events.UpdateCompleteEvent;
	
	import mx.utils.StringUtil;
	
	import uk.co.entropedia.display.ComponentStructure;
	import uk.co.entropedia.display.DialogComponent;
	import uk.co.entropedia.display.DialogUISlider;
	import uk.co.entropedia.display.IDialogComponentEditor;
	import uk.co.entropedia.display.LabelHTML;
	
	[SWF(width=1024,height=768)]
	public class control_board_maker extends Sprite
	{
		public static const NAME : String = 'Control Board Maker v1.0.16';
		public static const INIT_CLASS_NAME : String = 'ControlBoard';
		public static const SELECTED_LABEL : String = 'selected : ';
		
		[Embed("ControlBoardTemplate.as",mimeType="application/octet-stream")]
		protected var controlBoardTemplateClass : Class;		
		
		protected var componentClass : Class;
		protected var dialogs : Vector.<IDialogComponentEditor> = new Vector.<IDialogComponentEditor>;
		protected var componentsCreated : Vector.<Component> = new Vector.<Component>();

		protected var containerList : ComponentStructure;
		
		protected var controlBoard : Component;
		
		protected var label : Label;
		protected var selectedComponent : Component;
		
		protected var useCode : Boolean = false;
		protected var codeInput : InputText;
		protected var className : String = INIT_CLASS_NAME;
				
		public function control_board_maker()
		{
			if( stage ) init();
			else addEventListener( Event.ADDED_TO_STAGE, handleAddedToStage );
			
		}
		
		protected function init():void
		{
			var title : Label = new Label( this, 0, 0, NAME );
			title.scaleX = title.scaleY = 2;
			var box : HBox = new HBox( this, 0, 40 );
			box.spacing = 10;
			var leftPanel : Panel = new Panel( box );
			leftPanel.setSize( 250, 480 );
			var items : VBox = new VBox( leftPanel, 10, 10 );
			var button : PushButton;
			new Label( items, 0, 0, 'Created Component');
			button = new PushButton( items, 0, 0, 'HBox', handleComponentAddButtonClicked );
			button = new PushButton( items, 0, 0, 'VBox', handleComponentAddButtonClicked );
			button = new PushButton( items, 0, 0, 'HUISlider', handleComponentAddButtonClicked );
			button = new PushButton( items, 0, 0, 'VUISlider', handleComponentAddButtonClicked );
			new Label( items, 0, 0, 'Structure ( click an item to select it )' );
			containerList = new ComponentStructure( items, 0, 0 );
			label = new Label( items, 0, 0, SELECTED_LABEL );
			
			new CheckBox( items, 0, 0, 'Only show when activate code entered', handleActivateOnCodeToggle );
			new Label( items, 0, 0, "Activate Code" );
			codeInput = new InputText( items, 0, 0, "" );
			new Label( items, 0, 0, "( visiblity toggled when code typed in flash window )" );
			
						
			controlBoard = new Window( box, 0, 0, className );
			
			Window( controlBoard ).draggable = false;
			
			controlBoard.setSize( 640, 480 );
			controlBoard.mouseChildren = false;
			controlBoard.mouseEnabled = true;
			controlBoard.buttonMode = true;
			controlBoard.addEventListener( MouseEvent.CLICK, handleControlBoardClick );
			controlBoard.addEventListener( Event.REMOVED, handleRemoved );
			controlBoard.addEventListener( Event.ADDED, handleAdded );
			registerComponent( controlBoard );

			
			var hbox : HBox = new HBox( items, 0,0 );
			new Label( hbox, 0, 0, "class name" );
			var classNameInput : InputText = new InputText( hbox, 0,0, "ControlBoard", handleClassNameChange );
			classNameInput.restrict = 'a-zA-Z';
			hbox = new HBox( items, 0, 0);
			new Label( hbox, 0,0, "window width");
			var widthField : InputText = new InputText( hbox,0,0, controlBoard.height.toString(), widthChange );
			hbox = new HBox(items,0,0);
			new Label( hbox, 0,0, "window height");
			var heightField : InputText = new InputText( hbox, 0, 0, controlBoard.width.toString(), heightChange );
			
			
			var footer : Label = new LabelHTML( this, 600, 525, 'by Paul Hayes, <u><a href="http://code.google.com/p/control-board-maker/">source</a></u>. Made with <u><a href="http://www.minimalcomps.com/">minimal components</a></u> by <u><a href="http://www.bit-101.com/">Keith Peters</a></u>' );
			footer.scaleX = footer.scaleY = 1;

			dialogs.push( new DialogUISlider(this, stage.stageWidth * 0.5 - 300, stage.stageHeight * 0.5 - 200) );
			dialogs.push( new DialogComponent(this, stage.stageWidth * 0.5, stage.stageHeight * 0.5 - 200, controlBoard) );			
			
			hbox = new HBox( items, 0,0 );
			button = new PushButton( hbox, 0, 0, 'Copy to Clipboard', handleCopyClick );
			button = new PushButton( hbox, 0, 0, 'Save as file', handleSaveClicked );
			
			addEventListener( TextEvent.LINK, handleSelectComponent );
			addEventListener( Event.CHANGE, handleChange );
			containerList.update( controlBoard );
			

		}
		
		protected function createComponent():void
		{
			var parent : Component = DialogComponent.nextContainerComponent( selectedComponent ) || controlBoard;
			
			var component : Component;
			
			switch( componentClass )
			{
				case HUISlider:
					component = ( new HUISlider( parent, 0, 0 ) );
				break;
				case VUISlider:
					component = ( new VUISlider( parent, 0, 0 ) );
				break;
				case VBox:
					component = ( new VBox( parent ) );
				break;
				case HBox:
					component = ( new HBox( parent ) );
				break;
			}
			
			registerComponent( component );
			
			select( component );
		}
		
		protected function registerComponent( c : Component ):void
		{
			c.tag = componentsCreated.length;
			componentsCreated.push( c );
		}
		
		protected function select( component : Component ):void
		{
			if( selectedComponent )
			{
				selectedComponent.transform.colorTransform = new ColorTransform();
				selectedComponent.draw();
			}
			
			selectedComponent = component;
			
			if( selectedComponent )
			{
				label.text = SELECTED_LABEL+getQualifiedClassName( selectedComponent ).replace(/^.+::/,'');
				selectedComponent.transform.colorTransform = new ColorTransform( 1,1,1,1,0x40,-0x20,-0x20 );
				selectedComponent.draw();
			}
			else
			{
				label.text = SELECTED_LABEL+' none';
			}
			
			
			dialogs.forEach(function(b:IDialogComponentEditor,i:int,a:Vector.<IDialogComponentEditor>):void{
				b.target = component;
			});
			
			containerList.update( controlBoard, selectedComponent );
		}
		
		protected function generateCode():String
		{
			var activateCode : String = ( useCode && codeInput.text.length > 0 ) ? printf('activationCode = "%s";\n',codeInput.text) : '' ;
			var componentNames : String = '\n';
			var componentContructors : String = '\n';
			
			var list : Vector.<DisplayObjectContainer> = new Vector.<DisplayObjectContainer>;
			list.push( controlBoard );
			var displayObject : DisplayObjectContainer;
			while( displayObject = list.shift() )
			{
				
				for(var i:int=0;i<displayObject.numChildren;i++)
				{
					var child : DisplayObjectContainer = displayObject.getChildAt(i) as DisplayObjectContainer;
					if( child ) list.push( child );
				}
				
				var component : Component = displayObject as Component;
				
				if( ! component || component.tag == -1 ) continue;
				var componentClass : Class = Object( component ).constructor;
				var componentClassName : String = getQualifiedClassName( component ).toString().replace(/::/,'.');
				var componentParent : Component = DialogComponent.nextComponent( component.parent );
				var componentName : String = getQualifiedClassName( component ).replace(/^[^:]+::/,'').toLowerCase() + component.tag;
				var parentName : String ; 
				if( componentParent ) parentName = getQualifiedClassName( componentParent ).replace(/^[^:]+::/,'').toLowerCase() + componentParent.tag
				else parentName = 'this';
				
				var indent : String = StringUtil.repeat('\t',2);
				var constructorIndent : String = StringUtil.repeat('\t',3);
					
				componentNames += printf('%spublic var %s : %s ;\n',constructorIndent,componentName,componentClassName);
				componentContructors += printf('%s%s = new %s( %s );\n',constructorIndent,componentName,componentClassName,parentName);
				
				switch( componentClass )
				{
					case Window:
						
						componentContructors += printf('%s%s.setSize(%f,%f);\n',constructorIndent,componentName,component.width,component.height);
						componentContructors += printf('%s%s.minimized = %s;\n',constructorIndent,componentName,false.toString());
						componentContructors += printf('%s%s.hasMinimizeButton = %s;\n',constructorIndent,componentName,true.toString());
						componentContructors += printf('%s%s.hasCloseButton = %s;\n',constructorIndent,componentName,true.toString());
						componentContructors += printf('%s%s.addEventListener(Event.CLOSE,handleClose);\n',constructorIndent,componentName);
						break;
					case VUISlider:
					case HUISlider:
						componentContructors += printf('%s%s.label="%s";\n',constructorIndent,componentName,UISlider(component).label);
						componentContructors += printf('%s%s.minimum = %f;\n',constructorIndent,componentName,UISlider(component).minimum);
						componentContructors += printf('%s%s.maximum = %f;\n',constructorIndent,componentName,UISlider(component).maximum);
						break;
				}
			}
			
			var template : String = new controlBoardTemplateClass;
			return printf( template, { classname : className, activateCode : activateCode, componentNames : componentNames, componentContructors : componentContructors } );
		}
		
		protected function output():void
		{
			Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, generateCode() );
		}
		
		protected function save():void
		{
			var file : FileReference = new FileReference();
			file.save( generateCode(),className+'.as');
		}
				
		protected function isContainerComponent( displayObject : DisplayObject ):Boolean
		{
			return ( displayObject is VBox || displayObject is HBox )
		}
		
		protected function handleComponentAddButtonClicked(e:Event):void
		{
			var target : PushButton = e.target as PushButton;
			componentClass = getDefinitionByName( "com.bit101.components."+target.label ) as Class;
						
			createComponent();
		}
		
		protected function handleActivateOnCodeToggle(e:Event):void
		{
			var checkBox : CheckBox = e.target as CheckBox;
			useCode = checkBox.selected;
		}
		
		protected function handleCopyClick(e:Event):void
		{
			output();
		}
		
		protected function handleSaveClicked(e:Event):void
		{
			save();
		}
		
		protected function handleAddedToStage(e:Event):void
		{
			init();
		}
		
		protected function handleControlBoardClick(e:Event):void
		{
			var p : Point = new Point( controlBoard.mouseX, controlBoard.mouseY );
			var matchedComponents : Vector.<Component> = new Vector.<Component>;
			for each(var c : Component in componentsCreated )
			{
				if( !c ) continue;
				var r : Rectangle = c.getBounds( controlBoard );
				if( r.containsPoint( p ) ) matchedComponents.push( c );
			}
			
			var lastComponentIsSelected : Boolean = false;
			var component : Component;
			matchedComponents.reverse();
			
			for each( c in  matchedComponents )
			{
				if( lastComponentIsSelected )
				{
					component = c;
					break;
				}
				if( selectedComponent == c ) lastComponentIsSelected = true;
			}
			
			if( ! component ) component = matchedComponents.shift();
			
			select( component );
			
		}
		
		protected function handleRemoved(e:Event):void
		{
			var target : Component = e.target as Component;
			if( ! target || target.tag == -1 ) return ;
			componentsCreated[ target.tag ] = null;
			
			select( DialogComponent.nextComponent( target.parent ) );
			
			var containerList : ComponentStructure = this.containerList;
			var controlBoard : Component = this.controlBoard;
			var selectedComponent : Component = this.selectedComponent;
			
			addEventListener( Event.ENTER_FRAME, function(e:Event):void{
				containerList.update( controlBoard, selectedComponent );
				removeEventListener( Event.ENTER_FRAME, arguments.callee );
			} );
		}
		
		protected function handleAdded(e:Event):void
		{
			var target : Component = e.target as Component;
			if( ! target || target.tag == -1 ) return ;
			
			componentsCreated[ target.tag ] = target;
			select( DialogComponent.nextComponent( target ) );
			
		}
		
		protected function handleSelectComponent(e:TextEvent):void
		{
			var index : int =  parseInt( e.text );
			
			if( index >= 0 ) select( componentsCreated[ index ] );
		}
		
		protected function handleChange(e:Event):void
		{
			containerList.update( controlBoard, selectedComponent );
		}
		
		protected function widthChange(e:Event):void
		{
			var inputField : InputText = e.currentTarget as InputText;
			var w : Number= parseFloat( inputField.text );
			if( w > 0 ) controlBoard.width = w;
		}
		
		protected function heightChange(e:Event):void
		{
			var inputField : InputText = e.currentTarget as InputText;
			var h : Number = parseFloat( inputField.text );
			if( h > 0 ) controlBoard.height = h;
			
		}
		
		protected function handleClassNameChange(e:Event):void
		{			
			var inputField : InputText = e.currentTarget as InputText;
			className = inputField.text;
			Window(controlBoard).title = className;
		}
	}
}